#!/usr/bin/python
# -*- coding: utf-8 -*-

__date__ = u"16 mars 2010"
__author__ = u"INRIA pyLot"

__all__ = [u'CMakeOption', u'CMakeOptionBook']

from _pylot.core.path import Path, FilePath
from _pylot.core.datum import Datum
from _pylot.core.utils import check_type, check_value
from _pylot.core.system import ENCODING
from _pylot.core.book import Book
from _pylot.data import regexpr

class CMakeOption (Datum) :
  u"""
  This class is designed for CMake option handling.
  Based on Datum, this class adds two fields.
  
  **abspath**, boolean. Defines if absolute or relative path form is used.
  For example, It's advisable to set abspath=True for CMAKE_INSTALL_PREFIX.
  
  **level**, unicode. Defines the option level. Three levels are available :
    - user : means this option can be changed by simple users
    - devel : <=> advanced. Means this option can be changed by developers not specialized in CMake
    - expert : only for expert
  """
  ordered_keys = tuple(list(Datum.ordered_keys) + [u'abspath', u'level'])
  csv_order = u';'.join(ordered_keys)

  def _setabspath(self, abspath) :
    self._abspath = self.convert(abspath, bool)
    if self._abspath :
      self.value = self.value
      self.default_value = self.default_value
      self.value_list = self.value_list

  def _setlevel(self, level) :
    level = self.convert(level, unicode)
    if level and isinstance(level, unicode):
      check_value(u'level', level, [u'user', u'devel', u'expert'])
    else :
      level = u'user'
    self._level = level

  abspath = property(
    fget=lambda self: self._abspath,
    fset=_setabspath)

  level = property(
    fget=lambda self: self._level,
    fset=_setlevel)

  @classmethod
  def pyBoolToCMakeBool (cls, src):
    u"""
    >>> CMakeOption.pyBoolToCMakeBool(True)
    u'ON'
    """
    if src is True :
      return u'ON'
    elif src is False :
      return u'OFF'
    else :
      check_type(u'src', src, bool)

  @classmethod
  def cmakeTypeToPythonType(cls, src):
    u"""
    >>> CMakeOption.cmakeTypeToPythonType(u'BOOL')
    <type 'bool'>
    """
    check_type(u'src', src, unicode)
    cmake_to_py = {u'BOOL':bool,
                   u'STRING':unicode,
                   u'PATH':Path,
                   u'FILEPATH':FilePath}
    return cmake_to_py[src.upper()]

  def convert(self, val, nat):
    u"""
    Like Datum.convert but recognizes field "abspath"
    """
    val = super(CMakeOption, self).convert(val, nat)
    if val and issubclass(nat, Path) and self.abspath is True :
      return val.abspath()
    return val

  def toCMakeVarStr (self):
    u"""
    converts datum to cmake variable (cmake command line mode)
    
    >>> print CMakeOption(u'NAME', bool, False).toCMakeVarStr()
    -DNAME=OFF
    >>> print CMakeOption(u'NAME', unicode, u'-DVAR1=val1 -DVAR2=val2').toCMakeVarStr()
    -DNAME="-DVAR1=val1 -DVAR2=val2"
    """
    if self.value is not None :
      opt = self.name
      if self.nature == bool :
        return u'-D%s=%s' % (opt, self.pyBoolToCMakeBool(self.value))
      elif issubclass(self.nature, Path) :
        return u'-D%s=%s' % (opt, self.value.shellpath())
      else :
        if unicode(self.value).strip() :
          return u'-D%s="%s"' % (opt, self.value)
        else :
          return u'-D%s=' % opt
    return None

  @classmethod
  def FromCMakeOptionStr(cls, src):
    u"""
    >>> print CMakeOption.FromCMakeOptionStr(u'VAR:BOOL=ON')
    CMakeOption(u'VAR', bool, True)
    """
    datum = cls()
    datum.upFromCMakeOptionStr(src)
    return datum

  def upFromCMakeOptionStr (self, src):
    u"""
    >>> opt = CMakeOption()
    >>> opt.upFromCMakeOptionStr(u'VAR:FILEPATH=libpyLot.so')
    >>> print opt
    CMakeOption(u'VAR', FilePath, FilePath(u'libpyLot.so'))
    """
    if regexpr.co_cmake_option.match(src.strip()) :
      elements = src.strip().split(u'=') # Warning: line can be VAR:STRING=-DA=B
      variable = elements[0] # cmake var name and type ex "VAR:STRING"
      value = '='.join(elements[1:]) # variable value ex "-DA=B" 
      variable, nature = variable.split(u':') # VAR:STRING -> [VAR, STRING]

      self.nature = self.cmakeTypeToPythonType(nature)
      self.name = variable
      self.level = u'expert'
      self.group = u'miscellaneous'
      if u'NOTFOUND' in value :
        self.value = None
      else :
        self.value = value
        self.default_value = value
    else :
      pass

class CMakeOptionBook(Book):
  u"""
  A Book for CMakeOption objetcs
  
  >>> options = CMakeOptionBook()
  >>> options[u'opt1'] = True
  >>> print options[u'opt1'].toCMakeVarStr()
  -Dopt1=ON
  """
  def __init__ (self, *args, **kargs):

    # TODO: Python3: remove lines from here ...
    new_dict = {}
    for key, value in kargs.items() :
      new_dict[key.encode(ENCODING)] = value
    # ... to here
    new_dict['datum_type'] = CMakeOption

    super(CMakeOptionBook, self).__init__(*args, **new_dict)

if __name__ == '__main__':
  import doctest
  doctest.testmod()
